package com.wmx.eureka_client2020.controller;

import com.wmx.eureka_client2020.config.MyWebMvcConfigurer;
import com.wmx.eureka_client2020.pojo.ReturnData;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.swing.filechooser.FileSystemView;
import java.io.*;
import java.net.URLEncoder;
import java.util.*;

/**
 * Spring Boot 文件上传与下载、url 映射虚拟路径
 * Html5 + From 多、单文件上传
 *
 * @author wangMaoXiong
 * Created by Administrator on 2019/3/17 0017.
 */
@Controller
public class UploadFileController {

    private static final Logger logger = LoggerFactory.getLogger(UploadFileController.class);

    /**
     * 请求 url 中的资源映射，不推荐写死在代码中，最好提供可配置，如 /uploadFiles/**
     */
    @Value("${uploadFile.resourceHandler}")
    private String resourceHandler;

    /**
     * 上传文件保存的本地目录，使用 @Value获 取全局配置文件中配置的属性值，如 E:/wmx/uploadFiles/
     */
    @Value("${uploadFile.location}")
    private String uploadFileLocation;

    /**
     * http://localhost:8080/fileServer/uploadFile
     * 文件上传，因为只是演示，所以使用 @ResponseBody 将结果直接返回给页面
     *
     * @param singleFile ：上传的文件对象, 名称必须和页面<input type="file" name="xxx"/>的name属性值一致
     * @param request    ：请求对象
     * @return ：返回的是文件名称，将来客户端可以用来下载
     * @throws IOException
     */
    @PostMapping("uploadFile")
    @ResponseBody
    public String uploadFile(MultipartFile singleFile, HttpServletRequest request) throws IOException {
        if (singleFile == null || singleFile.isEmpty()) {
            logger.debug("上传文件为空...");
            return "上传文件为空...";
        }
        //basePath拼接完成后，形如：http://192.168.1.20:8080/fileServer
        String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath();
        String fileName = singleFile.getOriginalFilename();
        String fileServerPath = basePath + resourceHandler.substring(0, resourceHandler.lastIndexOf("/") + 1) + fileName;
        logger.debug("文件访问路径：{}", fileServerPath);

        File saveFile = new File(uploadFileLocation, fileName);
        /**
         * 文件保存，注意目的文件夹必须事先存在，否则保存时报错
         * 在{@link MyWebMvcConfigurer}中已经处理了，如果不存在，自动新建存储目录
         */
        singleFile.transferTo(saveFile);
        logger.info("文件保存路径：{}", saveFile.getPath());
        return "<a target='_blank' href='" + fileServerPath + "'>" + fileServerPath + "</a>";
    }

    /**
     * http://localhost:8080/fileServer/singleFileUpload
     * 单文件上传
     *
     * @param uploadFile：SpringMVC文件上传封装对象，多文件上传时，使用MultipartFile列表(List)或者数组(Array)都可以
     */
    @RequestMapping("singleFileUpload")
    @ResponseBody
    @SuppressWarnings("Duplicates")
    public Map<String, Object> singleFileUpload(@RequestParam MultipartFile uploadFile) throws IOException {
        // String getOriginalFilename() : 包含文件名与格式，如:123.mp4
        // long getSize() ：返回文件的大小（字节）。如果为空，则为0
        // String getContentType() ：返回内容类型，如果未定义，则返回{@code null}（或在多部分表单中未选择任何文件）
        // String byteCountToDisplaySize(final long size)：返回文件大小的可读版本,如 20.77M
        String fileNameAndFormat = uploadFile.getOriginalFilename();
        Long fileSizeLong = uploadFile.getSize();
        String contentType = uploadFile.getContentType();
        String fileSizeStr = FileUtils.byteCountToDisplaySize(fileSizeLong);

        File homeDirectory = FileSystemView.getFileSystemView().getHomeDirectory();
        File file = new File(homeDirectory, fileNameAndFormat);
        uploadFile.transferTo(file);

        Map<String, Object> map = new HashMap<>(8);
        map.put("fileNameAndFormat", fileNameAndFormat);
        map.put("fileSizeLong", fileSizeLong);
        map.put("fileSizeStr", fileSizeStr);
        map.put("contentType", contentType);
        map.put("transferTo", file.getAbsolutePath());

        // {
        //     "fileNameAndFormat":"Firefox-latest.exe",
        //     "fileSizeLong":394192,
        //     "transferTo":"E:\\桌面\\Firefox-latest.exe",
        //     "contentType":"application/x-msdownload"
        // }
        return map;
    }

    /**
     * http://localhost:8080/fileServer/multipleFileUpload
     * 单文件上传
     *
     * @param multipleFile：SpringMVC文件上传封装对象，多文件上传时，使用MultipartFile列表(List)或者数组(Array)都可以
     */
    @RequestMapping("multipleFileUpload")
    @ResponseBody
    @SuppressWarnings("Duplicates")
    public List<Map<String, Object>> multipleFileUpload(@RequestParam List<MultipartFile> multipleFile) throws IOException {
        List<Map<String, Object>> mapList = new ArrayList<>();
        for (MultipartFile uploadFile : multipleFile) {
            // String getOriginalFilename() : 包含文件名与格式，如:123.mp4
            // long getSize() ：返回文件的大小（字节）。如果为空，则为0
            // String getContentType() ：返回内容类型，如果未定义，则返回{@code null}（或在多部分表单中未选择任何文件）
            String fileNameAndFormat = uploadFile.getOriginalFilename();
            Long fileSizeLong = uploadFile.getSize();
            String contentType = uploadFile.getContentType();

            File homeDirectory = FileSystemView.getFileSystemView().getHomeDirectory();
            File file = new File(homeDirectory, fileNameAndFormat);
            uploadFile.transferTo(file);

            Map<String, Object> map = new HashMap<>(8);
            map.put("fileNameAndFormat", fileNameAndFormat);
            map.put("fileSizeLong", fileSizeLong);
            map.put("contentType", contentType);
            map.put("transferTo", file.getAbsolutePath());
            mapList.add(map);
        }
        // {
        //     "fileNameAndFormat":"Firefox-latest.exe",
        //     "fileSizeLong":394192,
        //     "transferTo":"E:\\桌面\\Firefox-latest.exe",
        //     "contentType":"application/x-msdownload"
        // }
        return mapList;
    }

    /**
     * 文件下载 · 使用 FileInputStream 读取文件内容
     * http://localhost:8080/fileServer/download1?id=f41e995ba7454a9da1bcd975c7460fcd.png
     *
     * @param response
     * @param id       ：文件名称，如 小白猫.png
     * @return
     * @throws IOException
     */
    @RequestMapping(value = {"/download1"}, method = {RequestMethod.GET})
    public void download1(HttpServletResponse response, String id) {
        OutputStream outputStream = null;
        try {
            logger.debug("文件下载：{}", id);
            //构建文件输入流。推荐使用：org.apache.commons.io.FileUtils.readFileToByteArray
            File saveFile = new File(uploadFileLocation, id);
            if (!saveFile.exists()) {
                //设置头信息
                response.setContentType("text/html;charset=utf-8");
                PrintWriter writer = response.getWriter();
                writer.write("【" + id + "】文件不存在！");
                logger.warn("【{} 】文件不存在！", id);
                writer.flush();
                writer.close();
                return;
            }
            InputStream inputStream = new FileInputStream(saveFile);
            //设置返回类型，必须对文件名称进行编码，否则中午容易乱码
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(id, "UTF-8"));

            //写入输出流返回给客户端
            outputStream = new BufferedOutputStream(response.getOutputStream());
            int length;
            byte[] bytes = new byte[1024];
            while ((length = inputStream.read(bytes)) != -1) {
                outputStream.write(bytes, 0, length);
            }
            outputStream.flush();
            outputStream.close();
            logger.info("文件下载完成：{}", id);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.flush();
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 文件下载 · 使用 FileUtils.readFileToByteArray 读取文件内容
     * http://localhost:8080/fileServer/download2?id=f41e995ba7454a9da1bcd975c7460fcd.png
     *
     * @param response
     * @param id       ：文件名称，如 123.xtx
     * @return
     */
    @RequestMapping(value = {"/download2"}, method = {RequestMethod.GET})
    public void download2(HttpServletResponse response, String id) {
        OutputStream outputStream = null;
        try {
            logger.debug("文件下载：{}", id);
            File saveFile = new File(uploadFileLocation, id);
            if (saveFile.exists()) {
                //设置返回类型，必须对文件名称进行编码，否则中午容易乱码
                response.setContentType("application/octet-stream");
                response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(id, "UTF-8"));

                //构建文件输入流。推荐使用：org.apache.commons.io.FileUtils.readFileToByteArray
                byte[] byteArray = FileUtils.readFileToByteArray(saveFile);

                //写入输出流返回给客户端
                outputStream = new BufferedOutputStream(response.getOutputStream());
                if (byteArray != null && byteArray.length > 0) {
                    outputStream.write(byteArray);
                }
            } else {
                //设置头信息
                response.setContentType("text/html;charset=utf-8");
                PrintWriter writer = response.getWriter();
                writer.write("【" + id + "】文件不存在！");
                logger.warn("【{} 】文件不存在！", id);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.flush();
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        logger.info("文件下载完成：{}", id);
    }


    /**===================================================仿平台文件上传接口./start===================================================*/
    @RequestMapping(value = {"/frs2/file/v2/upload"}, method = {RequestMethod.POST})
    @ResponseBody
    public ReturnData<String> v2upload(@RequestParam("file") MultipartFile file,
                                       @RequestParam("region") String region,
                                       @RequestParam("userId") Long userId,
                                       String agency,
                                       String fileType,
                                       String fileno,
                                       String keywords,
                                       String summary,

                                       HttpServletResponse response) {
        response.setContentType("text/plain");
        ReturnData<String> re = new ReturnData();
        String id = UUID.randomUUID().toString().replace("-", "");
        try {
            logger.debug("文件上传：Filename={}，region={}，userId={}，agency={}，fileType={}，fileno={}，keywords={}，summary={}",
                    file.getOriginalFilename(), region, userId, agency, fileType, fileno, keywords, summary);

            String fileName = file.getOriginalFilename();
            File saveFile = new File(uploadFileLocation, fileName);
            file.transferTo(saveFile);

            logger.debug("文件保存成功：{}", saveFile.getPath());

            re.setStatus_code("0000");
            re.setReason("上传成功");
            re.setData(id);

        } catch (Exception e) {
            re.setStatus_code("9999");
            re.setReason(e.getMessage());
        }
        logger.debug("returnData", re);
        return re;
    }


    /**===================================================仿平台文件上传接口./end===================================================*/


}
